﻿using IOA.MES.Client.Models;
using IOA.MES.Client.Models.Response;
using NLog;
using S7.Net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace IOA.MES.Client.Top
{
    public delegate void SubmitTopSettingDel(TopMachineSetting model);
    public delegate void TopMachineStatusChangeDel(JCPLCClient client);
    public delegate void TopViaSiteDel(dynamic request);

    /// <summary>
    /// 金辰PLC
    /// </summary>
    public class JCPLCClient
    {
        private Logger logger = LogManager.GetCurrentClassLogger();
        private SubmitTopSettingDel submitTopSetting;
        private TopMachineStatusChangeDel statusChange;
        private TopViaSiteDel topViaSite;
        private Plc plc = null;
        private List<int> addresses = new List<int>
        {
            0, 4, 700, 704, 708, 712, 716, 720, 724, 728, 732, 736, 800, 804, 808, 812, 816, 820, 824, 828, 832, 836
        };
        private Dictionary<int, Dictionary<int, decimal?>> datas = new Dictionary<int, Dictionary<int, decimal?>>
        {
            { 1, new Dictionary<int, decimal?>() },
            { 2, new Dictionary<int, decimal?>() }
        };

        /// <summary>
        /// 链接状态（0:未连接，1:连接中，2:已连接，3:拒绝连接）
        /// </summary>
        public int ConnectStatus { get; internal set; }
        public MachineAddressSetting Machine { get; internal set; }

        public JCPLCClient(MachineAddressSetting machine, TopMachineStatusChangeDel statusChange, SubmitTopSettingDel submitTopSetting, TopViaSiteDel topViaSite)
        {
            this.Machine = machine;
            this.statusChange = statusChange;
            this.submitTopSetting = submitTopSetting;
            this.topViaSite = topViaSite;
            foreach (var address in addresses)
            {
                foreach (var item in datas)
                {
                    item.Value.Add(address, null);
                }
            }
        }

        public void TryConnect()
        {
            ConnectStatus = 1;
            var fstConnect = false;
            if (plc == null)
            {
                fstConnect = true;
                plc = new Plc(CpuType.S71200, Machine.Address, Machine.Rack, Machine.Slot);
            }
            try
            {
                logger.Debug($"开始连接PLC，设备：{this.Machine.MachineName}，层：{this.Machine.Floor}，IP：{this.Machine.Address}");
                plc.Open();
                logger.Debug($"PLC连接成功");
            }
            catch (Exception ex)
            {
                logger.Fatal(ex, $"连接层压机PLC失败，设备：{this.Machine.MachineName}，层：{this.Machine.Floor}，IP：{this.Machine.Address}");
            }
            ConnectStatus = plc.IsConnected ? 2 : 3;
            statusChange(this);

            if (fstConnect)
            {
                new TaskFactory().StartNew(() =>
                {
                    while (true)
                    {
                        if (ConnectStatus == 2)
                        {
                            ReadData();
                        }
                        Thread.Sleep(30000);
                    }
                });
            }
        }

        private void ReadData()
        {
            try
            {
                logger.Debug($"开始读取PLC数据，设备：{this.Machine.MachineName}，层：{this.Machine.Floor}，IP：{this.Machine.Address}");
                foreach (var layer in datas)
                {
                    foreach (var address in addresses)
                    {
                        var result = plc.Read(DataType.DataBlock, 100 + layer.Key, address, VarType.Real, 1);
                        layer.Value[address] = result == null ? (decimal?)null : Convert.ToDecimal(result);
                    }
                    logger.Debug($"层{layer.Key}读取完成");

                    try
                    {
                        submitTopSetting(new TopMachineSetting
                        {
                            MachineId = this.Machine.MachineId,
                            MachineName = this.Machine.MachineName,
                            Layer = Machine.Floor,
                            Cavity = layer.Key,
                            UpperVacuumDelayTime = layer.Value[700],
                            VacuumPumpingTime = layer.Value[704],
                            Pressure1 = layer.Value[708],
                            PressureDelayTime1 = layer.Value[712],
                            Pressure2 = layer.Value[716],
                            PressureDelayTime2 = layer.Value[720],
                            Pressure3 = layer.Value[724],
                            TopTime = layer.Value[728],
                            InflationTime = layer.Value[732],
                            Temp = layer.Value[736]
                        });
                    }
                    catch (Exception ex)
                    {
                        logger.Fatal(ex, $"提交层压机配置出错，设备：{this.Machine.MachineName}，层：{this.Machine.Floor}，IP：{this.Machine.Address}，腔体：{layer.Key}");
                    }

                    var barCodeBytes = new List<byte>();
                    for (var address = 100; address <= 449; address++)
                    {
                        barCodeBytes.Add(Convert.ToByte(plc.Read(DataType.DataBlock, 100 + layer.Key, address, VarType.Byte, 1)));
                    }
                    var barCodes = new List<string>
                    {
                        Encoding.ASCII.GetString(barCodeBytes.Skip(0).Take(50).ToArray()),
                        Encoding.ASCII.GetString(barCodeBytes.Skip(50).Take(50).ToArray()),
                        Encoding.ASCII.GetString(barCodeBytes.Skip(100).Take(50).ToArray()),
                        Encoding.ASCII.GetString(barCodeBytes.Skip(150).Take(50).ToArray()),
                        Encoding.ASCII.GetString(barCodeBytes.Skip(200).Take(50).ToArray()),
                        Encoding.ASCII.GetString(barCodeBytes.Skip(250).Take(50).ToArray()),
                        Encoding.ASCII.GetString(barCodeBytes.Skip(300).Take(50).ToArray())
                    }.Select(_ => _.Replace("NOREAD", "").Trim()).Where(_ => !string.IsNullOrWhiteSpace(_)).ToList();

                    if (!barCodes.Any())
                    {
                        logger.Info($"设备：{this.Machine.MachineName}，层：{this.Machine.Floor}，腔体：{layer.Key}，层压组件列表为空");
                        continue;
                    }

                    logger.Info($"设备：{this.Machine.MachineName}，层：{this.Machine.Floor}，腔体：{layer.Key}，层压组件列表：{string.Join(",", barCodes)}");
                    new TaskFactory().StartNew(() =>
                    {
                        foreach (var barCode in barCodes)
                        {
                            try
                            {
                                topViaSite(new
                                {
                                    SiteType = SiteType.Top,
                                    MachineId = this.Machine.MachineId,
                                    Code = barCode.Trim(),
                                    TopPosition = $"{this.Machine.Floor}层_{layer.Key}腔",
                                    TopData = new List<KeyValuePair<string, object>>
                                    {
                                        new KeyValuePair<string, object>("Layer", this.Machine.Floor),
                                        new KeyValuePair<string, object>("Cavity", layer.Key),
                                        new KeyValuePair<string, object>("WorkingStatus", layer.Value[4]),
                                        new KeyValuePair<string, object>("TableAvgTemp", layer.Value[800]),
                                        new KeyValuePair<string, object>("UpperVacuum", layer.Value[804]),
                                        new KeyValuePair<string, object>("DownVacuum", layer.Value[808]),
                                        new KeyValuePair<string, object>("OilTankTemp", layer.Value[812]),
                                        new KeyValuePair<string, object>("DownVacuumPsg", layer.Value[816]),
                                        new KeyValuePair<string, object>("Temp1", layer.Value[820]),
                                        new KeyValuePair<string, object>("Temp2", layer.Value[824]),
                                        new KeyValuePair<string, object>("Temp3", layer.Value[828]),
                                        new KeyValuePair<string, object>("Temp4", layer.Value[832]),
                                        new KeyValuePair<string, object>("Temp5", layer.Value[836])
                                    }
                                });
                            }
                            catch (Exception ex)
                            {
                                logger.Fatal(ex, $"过站失败：{barCode}");
                            }
                        }
                    });
                }
            }
            catch (Exception ex)
            {
                logger.Fatal(ex, $"读取PLC设备出错：{ex.Message}");
                ConnectStatus = 3;
            }
        }
    }
}
